package com.na.game.klotski.ui;

import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Rect;
import android.view.MotionEvent;

import com.na.game.engine.GameManager;
import com.na.game.engine.event.impl.TouchEvent;
import com.na.game.engine.graphics.Graphics;
import com.na.game.engine.graphics.Image;
import com.na.game.engine.graphics.Painter;
import com.na.game.engine.opengl.GLImage;
import com.na.game.engine.platform.PlatformApi;
import com.na.game.engine.resource.ResourceManager;
import com.na.game.engine.sound.SoundManager;
import com.na.game.engine.ui.UI;
import com.na.game.engine.ui.UIManager;
import com.na.game.engine.util.GameConfig;
import com.na.game.engine.util.Timer;
import com.na.game.engine.util.TimerTask;
import com.na.game.engine.util.Util;
import com.na.game.engine.widget.Layout;
import com.na.game.engine.widget.impl.Container;
import com.na.game.engine.widget.impl.Icon;
import com.na.game.engine.widget.impl.Label;
import com.na.game.klotski.entity.Game;
import com.na.game.klotski.entity.Item;
import com.na.game.klotski.entity.ItemType;
import com.na.game.klotski.util.GameUtil;

public class GameUI extends UI {

	private Label scoreLbl, timeLbl;
	private Icon[] icons;
	private Game game;
	
	private static final int COLOR_CURRENT = 0xff77c298;
	private static final int COLOR_HIDE = 0x7f77c298;
	
	public GameUI() {
	}
	
	private class IconHoldPainter implements Painter {
		private Icon owner;
		private long startTime;
		private IconHoldPainter(Icon owner) {
			this.owner = owner;
			startTime = System.currentTimeMillis();
		}
		@Override
		public void paint(Graphics g) {
			int angle = (int) ((System.currentTimeMillis() - startTime) / (float) GameUtil.HOLD_TIME * 360);
			if (angle > 360) {
				angle = 360;
			}
			int x = owner.getAbsX() + owner.getWidth() / 2;
			int y = owner.getAbsY() + owner.getHeight() / 2;
			g.setColor(0x33000000);
			g.fillArc(x, y, owner.getWidth() / 2, owner.getHeight() / 2, 90, angle);
		}
	}
	
	@Override
	public void init() {
		PlatformApi.invoke(PlatformApi.CMD_SHOW_BANNER);
		
		game = new Game();
		Container ui = new Container();
//		ui.setBackgroundColor(0xaaf7cfb5);
		ui.setBound(0, 0, GameConfig.STANDARD_WIDTH, GameConfig.STANDARD_HEIGHT);
		setWidget(ui);
		
		// score
		Label lbl = new Label("", Color.BLACK);
		ui.addChild(lbl);
		lbl.setTextSize(40);
//		lbl.setTextColor(0xfff76963);
		lbl.setTextAlign(Layout.CENTER);
		lbl.setBound(0, 0, GameConfig.STANDARD_WIDTH, 150);
		scoreLbl = lbl;
		// time
		lbl = new Label("", Color.BLACK);
		ui.addChild(lbl);
		lbl.setTextSize(35);
//		lbl.setTextColor(0xfff76963);
		lbl.setTextAlign(Layout.LEFT_CENTER);
		lbl.setBound(20, 0, 300, 150);
		timeLbl = lbl;
		
		icons = new Icon[4];
		for (int i = 0; i < 4; i++) {
			icons[i] = new Icon(null);
			ui.addChild(icons[i]);
		}
		
		// 1
		Item item = getRandomItem();
		int w = item.getImage().getWidth() >> 2;
		int h = item.getImage().getHeight() >> 2;
		int x = GameConfig.STANDARD_WIDTH - w >> 1;
		int y = 150;
		y -= h / 2; // correct
		Icon icon = icons[0];
		icon.setIcon(item.getImage());
		icon.setExtra(item);
		icon.setBound(x, y, w, h);
		icon.setScaled(true);
		icon.setSrcRect(new Rect(0, 0, item.getImage().getWidth(), item.getImage().getHeight()));
		icon.setImageColor(COLOR_HIDE);
		
		// 2
//		y += h + 80;
		y = 300;
		item = getRandomItem();
		w = item.getImage().getWidth() >> 1;
		h = item.getImage().getHeight() >> 1;
		x = GameConfig.STANDARD_WIDTH - w >> 1;
		y -= h / 2; // correct
		icon = icons[1];
		icon.setIcon(item.getImage());
		icon.setExtra(item);
		icon.setBound(x, y, w, h);
		icon.setScaled(true);
		icon.setSrcRect(new Rect(0, 0, item.getImage().getWidth(), item.getImage().getHeight()));
		icon.setImageColor(COLOR_HIDE);
		
		// 3
//		y += h + 200;
		y = 600;
		item = getRandomItem();
		w = item.getImage().getWidth();
		h = item.getImage().getHeight();
		x = GameConfig.STANDARD_WIDTH - w >> 1;
		y -= h / 2; // correct
		icon = icons[2];
		icon.setIcon(item.getImage());
		icon.setExtra(item);
		icon.setBound(x, y, w, h);
		icon.setScaled(true);
		icon.setSrcRect(new Rect(0, 0, item.getImage().getWidth(), item.getImage().getHeight()));
		icon.setImageColor(COLOR_CURRENT);
		game.setCurrent(item); // init
		
		// 4
//		y += h + 200;
		y = 900;
//		item = getRandomItem();
		w = 1;//item.getImage().getWidth() >> 2;
		h = 1;//item.getImage().getHeight() >> 2;
		x = GameConfig.STANDARD_WIDTH - w >> 1;
		y -= h / 2; // correct
		icon = icons[3];
		icon.setBound(x, y, w, h);
		icon.setScaled(true);
		icon.setSrcRect(new Rect(0, 0, item.getImage().getWidth(), item.getImage().getHeight()));
		icon.setImageColor(COLOR_HIDE);
	}
	
	private Item getRandomItem() {
		int index = Util.RND.nextInt(ItemType.values().length);
		ItemType type = ItemType.toType(index);
		String path = null;
		switch (type) {
			case CLICK:
				path = "image/click.png";
				break;
			case DOUBLE_CLICK:
				path = "image/click2.png";
				break;
			case HOLD:
				path = "image/hold.png";
				break;
			case TO_RIGHT:
				path = "image/swipe.png";
				break;
			case REVERSE_RIGHT:
				path = "image/swipe2.png";
				break;
		}
		if (path != null) {
			Image image = GameManager.get(ResourceManager.class).getImageFromAssets(path);
			if (GameConfig.useOpenGL) {
				((GLImage) image).setRecyclable(false);
			}
			return new Item(image, type);
		}
		int trans = Graphics.TRANS_NONE;
		path = "image/swipe2.png";
		switch (type) {
			case TO_UP:
				path = "image/swipe.png";
			case REVERSE_UP:
				trans = Graphics.TRANS_ROT270;
				break;
			case TO_DOWN:
				path = "image/swipe.png";
			case REVERSE_DOWN:
				trans = Graphics.TRANS_ROT90;
				break;
			case TO_LEFT:
				path = "image/swipe.png";
			case REVERSE_LEFT:
				trans = Graphics.TRANS_MIRROR;
				break;
		}
		Image src = GameManager.get(ResourceManager.class).getImageFromAssets(path);
		Bitmap bitmap = Bitmap.createBitmap(src.getBitmap(), 0, 0, src.getWidth(), src.getHeight(), Graphics.transformMatrix(trans), true);
		Image image = Util.wrapImage(bitmap);
		return new Item(image, type);
	}
	
	private void nextItem() {
		// move item
		for (int i = icons.length - 1; i > 0; i--) {
			Item item = (Item) icons[i - 1].getExtra();
			icons[i].setExtra(item);
			icons[i].setIcon(item.getImage());
		}
		Item item = getRandomItem();
		icons[0].setExtra(item);
		icons[0].setIcon(item.getImage());
		// rebounds
		int x = 0, w = 0, h = 0;
		int[] y = { 150, 300, 600, 900 };
		for (int i = 0; i < icons.length; i++) {
			Icon icon = icons[i];
			icon.setPainter(null);
			item = (Item) icon.getExtra();
			if (i == 0 || i == 3) {
				w = item.getImage().getWidth() >> 2;
				h = item.getImage().getHeight() >> 2;
			} else if (i == 1) {
				w = item.getImage().getWidth() >> 1;
				h = item.getImage().getHeight() >> 1;
			} else {
				w = item.getImage().getWidth();
				h = item.getImage().getHeight();
			}
			x = GameConfig.STANDARD_WIDTH - w >> 1;
			y[i] -= h / 2; // correct
			icon.setBound(x, y[i], w, h);
			icon.setScaled(true);
			icon.setSrcRect(new Rect(0, 0, item.getImage().getWidth(), item.getImage().getHeight()));
		}
		// update
		game.setCurrent((Item) icons[2].getExtra());
	}

	boolean pressed, dragged, dragging;
	long clickTime;
	int clickCount;
	int pressedX, pressedY;
	@Override
	public boolean onTouch(TouchEvent event) {
		if (game.end()) {
			return true;
		}
		switch (event.action) {
			case MotionEvent.ACTION_DOWN:
				pressed = true;
				dragged = false;
				dragging = false;
				pressedX = event.x;
				pressedY = event.y;
				if (clickTime != 0 && System.currentTimeMillis() - clickTime >= GameUtil.HOLD_TIME) {
					if (clickCount == 1 && game.checkDoubleClickError()) {
						clickCount = 0;
					} else {
						clickCount++;
					}
				} else {
					clickCount++;
				}
				clickTime = System.currentTimeMillis();
				touchDown();
				break;
			case MotionEvent.ACTION_MOVE:
				if (dragging) {
					break;
				}
				int xoffset = event.x - pressedX;
				int yoffset = event.y - pressedY;
				int absx = Math.abs(xoffset);
				int absy = Math.abs(yoffset);
				if (absx > 20 || absy > 20) {
					dragged = true;
					dragging = true;
					if (absx > absy) { // horizontal
						if (xoffset > 0)
							moveToRight();
						else
							moveToLeft();
					} else {
						if (yoffset > 0)
							moveToDown();
						else
							moveToUp();
					}
				}
				break;
			case MotionEvent.ACTION_UP:
				if (dragged) {
					clickCount = 0;
				} else {
					long elapse = System.currentTimeMillis() - clickTime;
					if (elapse < GameUtil.HOLD_TIME) {
						if (clickCount == 1 && click()) {
							clickCount = 0;
						}
						if (clickCount == 2) {
							clickCount = 0;
							doubleClick();
						}
					} else {
						clickCount = 0;
						holdTouch();
					}
				}
				touchUp();
				clickTime = System.currentTimeMillis();
				break;
		}
		return true;
	}
	
	private void moveToUp() {
		if (game.moveToUp()) {
			nextItem();
		}
	}
	private void moveToDown() {
		if (game.moveToDown()) {
			nextItem();
		}
	}
	private void moveToLeft() {
		if (game.moveToLeft()) {
			nextItem();
		}
	}
	private void moveToRight() {
		if (game.moveToRight()) {
			nextItem();
		}
	}
	private boolean click() {
		if (game.click()) {
			nextItem();
			return true;
		}
		return false;
	}
	private void doubleClick() {
		if (game.doubleClick()) {
			nextItem();
		}
	}
	private void holdTouch() {
		if (game.holdTouch()) {
			nextItem();
		}
	}
	
	private void touchDown() {
		if (game.getCurrent().getType() == ItemType.HOLD) {
			Icon icon = icons[2];
			icon.setPainter(new IconHoldPainter(icon));
		}
	}
	
	private void touchUp() {
	}

	private boolean ended;
	@Override
	public void update() {
		super.update();
		if (ended) {
			return;
		}
		game.update();
		if (game.end()) {
			ended = true;
			PlatformApi.invoke(PlatformApi.CMD_SHOW_POP_AD);
			if (game.getScore() >= 30) {
				GameManager.get(SoundManager.class).play("sounds/cheer.m4a");
			}
			new Timer().schedule(new TimerTask() {
				@Override
				public void execute() {
					UIManager manager = GameManager.get(UIManager.class);
					manager.popUI();
					manager.pushUI(new GameEndUI(game));
				}
			}, 1000);
//			GameUtil.updateGameScore(game.getScore());
		} else {
			scoreLbl.setText(String.valueOf(game.getScore()));
			timeLbl.setText(game.getRemainSeconds() + " s");
		}
	}
	
}
